package com.crud.demo1.demos.commons.aop;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.util.UUID;

/**
 * @author zhangning
 * @since 2025/2/27 13:36
 */

@Slf4j
@Aspect
@Component
public class LoggingAspect {

    private static final ObjectMapper objectMapper = new ObjectMapper();

    @Pointcut("execution(* com.crud.demo1.demos.controller..*.*(..))")
    public void excudeService(){

    }

   // @Around("execution(* com.crud.demo1.demos.controller..*.*(..))")
    @Around("excudeService()")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        // 生成Trace ID
        String traceId = UUID.randomUUID().toString();
        MDC.put("traceId", traceId);

        // 获取方法信息
        String methodName = joinPoint.getSignature().getName();
        String className = joinPoint.getTarget().getClass().getSimpleName();

        // 获取方法参数并格式化为 JSON
        Object[] args = joinPoint.getArgs();
        StringBuilder params = new StringBuilder();
        for (Object arg : args) {
            try {
                String argName = arg.getClass().getSimpleName();
                params.append(argName + "=");
                params.append(objectMapper.writeValueAsString(arg)).append(", ");
            } catch (Exception e) {
                params.append(arg.toString()).append(", ");
            }
        }
        if (params.length() > 0) {
            params.delete(params.length() - 2, params.length()); // 删除最后的逗号和空格
        }
        // 记录方法开始日志 （包含参数）
        log.info("Entering method:{ {}.{} } with arguments: [{}]", className, methodName, params);

        try {
            // 执行目标方法
            Object result = joinPoint.proceed();

            // 记录方法结束日志
            log.info("Exiting method:{ {}.{} } with result: {}", className, methodName, result);
            return result;
        } catch (Exception e) {
            // 记录异常日志
            log.error("Exception in method:{ {}.{} }- {}", className, methodName, e.getMessage());
            throw e;
        } finally {
            // 清除Trace ID
            MDC.remove("traceId");
        }
    }

    /**
     * 打印请求接口的路径
     * @param joinPoint .
     */
    @Before("excudeService()") // 拦截 controller 包下的所有方法
    public void logRequestPath(JoinPoint joinPoint) {
        ServletRequestAttributes attributes = (ServletRequestAttributes)
                RequestContextHolder.getRequestAttributes();
        if (attributes != null) {
            String path = attributes.getRequest().getRequestURI();
            log.info("Request Path (AOP): {}", path);
        }
    }
}